package workflow

import (
	"encoding/json"
	"fmt"
	"project-info/src/constants"
	"project-info/src/handle/common"
	"project-info/src/handle/response"
	"project-info/src/lib"
	"project-info/src/model"
	"project-info/src/service"
	"slices"
	"github.com/expr-lang/expr"
)

// 权限判断标识
const NeedPermissionJudge = "need_permission_judge"

// SaveWorkflow 添加工作流
func SaveWorkflow(c *lib.GinContext) error {
	//1. 解析参数
	var workflowReq WorkflowReq
	if err := c.Bind(&workflowReq); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	// 构建工作流对象
	workflow := &model.Workflow{
		Name:        workflowReq.BasicInfo.Name,
		Description: workflowReq.BasicInfo.Description,
		FormConfig:  workflowReq.FormConfig,
		FlowConfig:  workflowReq.FlowConfig,
		Metadata:    workflowReq.Metadata,
	}
	workflow.Id = workflowReq.Id

	result := model.DBWithGinContext(c).Save(&workflow)

	if result.Error != nil {
		c.Logger().Error("保存工作流失败: " + result.Error.Error())
		return response.JsonFail(c, "保存工作流失败")
	}
	return response.JsonOk(c, workflow)
}

// PageWorkflow 分页查询工作流
func PageWorkflow(c *lib.GinContext) error {
	var pageWorkflowReq *WorkflowPageReq
	if err := c.Bind(&pageWorkflowReq); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	start, end := lib.Paging(pageWorkflowReq.Page, pageWorkflowReq.Size)

	var workflows []*model.Workflow
	var total int64

	db := model.DB().Model(&model.Workflow{})
	if pageWorkflowReq.Name != "" {
		db.Where("name like ?", fmt.Sprintf("%%%s%%", pageWorkflowReq.Name))
	}
	db.Where("deleted = 0").Count(&total).Order("id desc").Offset(start).Limit(end).Find(&workflows)

	//3. 转换为页面格式
	var workflowPageRecords []*WorkflowPageRecord
	for _, workflow := range workflows {
		workflowPageRecords = append(workflowPageRecords, &WorkflowPageRecord{
			Id:         workflow.Id,
			BasicInfo:  BasicInfo{Name: workflow.Name, Description: workflow.Description},
			FormConfig: workflow.FormConfig,
			FlowConfig: workflow.FlowConfig,
			Metadata:   workflow.Metadata,
			CreateTime: workflow.CreateTime,
			UpdateTime: workflow.UpdateTime,
		})
	}

	return response.JsonOk(c, &common.PageRes{
		Total:   total,
		Records: workflowPageRecords,
	})
}

// GetWorkflowList 获取工作流列表
func GetWorkflowList(c *lib.GinContext) error {
	var getWorkflowListReq GetWorkflowListReq
	if err := c.Bind(&getWorkflowListReq); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	var workflows []*model.Workflow
	db := model.DB().Model(&model.Workflow{})
	if getWorkflowListReq.Name != "" {
		db.Where("name like ?", fmt.Sprintf("%%%s%%", getWorkflowListReq.Name))
	}
	db.Where("deleted = 0").Find(&workflows)

	return response.JsonOk(c, workflows)
}

// StartWorkflow 启动工作流
func StartWorkflow(c *lib.GinContext) error {
	var req StartWorkflowReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	//1. 查询工作流
	var workflow model.Workflow
	model.DB().Where("id = ?", req.WorkflowId).First(&workflow)

	//2. 启动工作流
	var node Node
	err := json.Unmarshal(workflow.FlowConfig, &node)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "解析工作流失败")
	}

	token := lib.JwtParse(c)

	//2.1 存储工作流实例
	workflowInstance := &model.WorkflowInstance{
		WorkflowId:   req.WorkflowId,
		WorkflowName: req.WorkflowName,
		FormConfig:   workflow.FormConfig,
		Variables:    req.Variables,
		Status:       constants.WorkflowInstanceStatusRunning,
		Priority:     req.Priority,
	}

	result := model.DBWithGinContext(c).Create(workflowInstance)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "启动工作流失败")
	}

	err = startNewNode(c, node, nil, workflowInstance, token)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "保存工作流节点失败")
	}

	return response.JsonOk(c, "ok")
}

// startNewNode 启动新节点
func startNewNode(c *lib.GinContext, node Node, parentNodes []Node, workflowInstance *model.WorkflowInstance, token *lib.Token) error {
	nodeStatus := constants.NodeStatusCreate
	if node.Type == constants.NodeTypeApprove {
		nodeStatus = constants.NodeStatusApproving
	}
	nodeDb, err := saveNode2Db(node, parentNodes, workflowInstance, nodeStatus, token)
	if err != nil {
		return err
	}

	if node.Type == constants.NodeTypeApprove {
		// 审批节点,需要保存审批人
		var nodeAssignees []model.NodeAssignee
		for _, user := range node.NodeUserList {
			nodeAssignees = append(nodeAssignees, model.NodeAssignee{
				WorkflowInstanceId: nodeDb.WorkflowInstanceId,
				NodeId:             nodeDb.Id,
				Type:               user.Type,
				TargetId:           user.TargetId,
				Name:               user.Name,
			})
		}
		create := model.DB().Create(&nodeAssignees)
		if create.Error != nil {
			return create.Error
		}
	}

	if node.Type != constants.NodeTypeApprove {
		// 非审批节点,自动完成节点
		completeNode(c, node, parentNodes, workflowInstance, nodeDb, token, "")
	}
	return nil
}

// saveNode2Db 保存节点到数据库
func saveNode2Db(node Node, parentNodes []Node, workflowInstance *model.WorkflowInstance, status string, token *lib.Token) (*model.Node, error) {
	childNode, err := json.Marshal(node.ChildNode)
	if err != nil {
		return nil, err
	}

	conditionNodes, err := json.Marshal(node.ConditionNodes)
	if err != nil {
		return nil, err
	}

	parentStackNodes, err := json.Marshal(parentNodes)
	if err != nil {
		return nil, err
	}

	//2.2 存储工作流节点实例,并更新工作流实例当前节点
	nodeDb := &model.Node{
		WorkflowInstanceId: workflowInstance.Id,
		NodeName:           node.NodeName,
		Type:               node.Type,
		ChildNode:          childNode,
		ExamineMode:        node.ExamineMode,
		ConditionNodes:     conditionNodes,
		Condition:          node.Condition,
		ParentNodes:        parentStackNodes,
		Status:             status,
	}

	result := model.DBWithToken(token).Create(nodeDb)
	if result.Error != nil {
		return nil, result.Error
	}

	updateMap := map[string]interface{}{
		"current_node_id":   nodeDb.Id,
		"current_node_name": nodeDb.NodeName,
	}

	if status == constants.NodeStatusApproving {
		updateMap["status"] = constants.WorkflowInstanceStatusApproving
	} else {
		updateMap["status"] = constants.WorkflowInstanceStatusRunning
	}

	updates := model.DBWithToken(token).Model(&model.WorkflowInstance{}).Where("id = ?", workflowInstance.Id).Updates(updateMap)
	if updates.Error != nil {
		return nil, updates.Error
	}
	return nodeDb, nil
}

// completeNode 完成节点
func completeNode(c *lib.GinContext, node Node, parentNodes []Node, workflowInstance *model.WorkflowInstance, nodeDb *model.Node, token *lib.Token, comment string) error {
	var nodeActionHistory = &model.NodeActionHistory{
		WorkflowInstanceId: workflowInstance.Id,
		NodeId:             nodeDb.Id,
		NodeName:           nodeDb.NodeName,
		NodeType:           node.Type,
		Comment:            comment,
	}

	// 统一设置为通过,特殊: 审批节点会签在所有审批完成后再设置为通过
	nodeDb.Status = constants.NodeStatusPass

	switch node.Type {
	case constants.NodeTypeStart:
		if node.ChildNode != nil {
			nodeActionHistory.Type = constants.NodeActionTypeStart
			nodeActionHistory.ActionInfo = getOperatorActionInfoJson(token)
			startNewNode(c, *node.ChildNode, parentNodes, workflowInstance, token)
		}
	case constants.NodeTypeApprove:
		nodeOperatorAction := constants.NodeActionTypeOrApprove
		if node.ExamineMode == 2 {
			// 会签操作
			nodeOperatorAction = constants.NodeActionTypeAndApprove
		}
		// 保存用户审批结果
		nodeOperator := model.NodeOperator{
			WorkflowInstanceId:     workflowInstance.Id,
			NodeId:                 nodeDb.Id,
			NodeName:               nodeDb.NodeName,
			OperatorId:             token.UserId,
			Operator:               token.UserName,
			Action:                 nodeOperatorAction,
			WorkflowInstanceStatus: constants.WorkflowInstanceStatusRunning,
		}
		model.DBWithToken(token).Create(&nodeOperator)

		// 查询所有的审批人
		nodeAllAssigneeList := []model.NodeAssignee{}
		result := model.DB().Where("workflow_instance_id = ? and node_id = ?", workflowInstance.Id, nodeDb.Id).Find(&nodeAllAssigneeList)
		if result.Error != nil {
			return result.Error
		}
		if node.ExamineMode == 2 {
			// 查询用户对应的角色id
			roleIds, _ := service.GetRoleIdsByUserId(c, token.UserId)
			// 循环判断assigneeList是否在角色id和用户id中
			fromNodeAssignees := []model.NodeAssignee{}
			for _, assignee := range nodeAllAssigneeList {
				if (assignee.Type == constants.NodeAssigneeTypeUser && assignee.TargetId == token.UserId) || (assignee.Type == constants.NodeAssigneeTypeRole && slices.Contains(roleIds, assignee.TargetId)) {
					fromNodeAssignees = append(fromNodeAssignees, assignee)
				}
			}
			// 删除当前用户的审批权限,包含用户和用户的角色,当用户和角色同时在审批权限中,相当于都删除
			if len(fromNodeAssignees) != 0 {
				if err := model.DB().Delete(&fromNodeAssignees).Error; err != nil {
					return err
				}
			}

			// 会签节点,判断是否所有审批人都审批了
			if len(nodeAllAssigneeList) > len(fromNodeAssignees) {
				nodeDb.Status = constants.NodeStatusApproving
			}

			// 会签节点,需要保存审批人
			nodeActionHistory.Type = constants.NodeActionTypeAndApprove
			// 获取最新的审批人和审批过的人
			actionInfo := getAssigneeAndOperatorActionInfoMap(nodeDb)
			// 当前用户审批后删除的审批权限,历史记录
			actionInfo["deletedAssignees"] = fromNodeAssignees
			nodeActionHistory.ActionInfo = transferActionInfoJson(actionInfo)
		} else {
			// 或签节点,将Node对应所有NodeAssignee记录删除
			if len(nodeAllAssigneeList) != 0 {
				if err := model.DB().Delete(&nodeAllAssigneeList).Error; err != nil {
					return err
				}
			}
			nodeActionHistory.Type = constants.NodeActionTypeOrApprove
			nodeActionHistory.ActionInfo = transferActionInfoJson(map[string]interface{}{
				"operator": []model.NodeOperator{nodeOperator},
			})
		}

		if nodeDb.Status == constants.NodeStatusPass && node.ChildNode != nil {
			startNewNode(c, *node.ChildNode, parentNodes, workflowInstance, token)
		}
	case constants.NodeTypeCondition:
		nodeActionHistory.Type = constants.NodeActionTypeCondition
		// 完成条件节点,需要判断条件
		for i, conditionNode := range node.ConditionNodes {
			if conditionNode.Condition == "" {
				// 最后一个条件节点,且条件为空,相当于默认执行
				if i != len(node.ConditionNodes)-1 {
					continue
				}
			} else {
				// 根据conditionNode.Condition判断条件,为true则执行conditionNode的childNode节点，同时将当前节点的childNode添加到parentNodes中，用于回溯
				output, err := evalNodeCondition(conditionNode, workflowInstance)
				if err != nil {
					return err
				}

				if output == nil || output == false {
					continue
				}
			}
			// 保存具体条件节点的执行结果
			_, err := saveNode2Db(*conditionNode, parentNodes, workflowInstance, constants.NodeStatusPass, token)
			if err != nil {
				return err
			}

			if node.ChildNode != nil {
				if parentNodes == nil {
					parentNodes = []Node{*node.ChildNode}
				} else {
					parentNodes = append([]Node{*node.ChildNode}, parentNodes...)
				}
			}

			if conditionNode.ChildNode != nil {
				startNewNode(c, *conditionNode.ChildNode, parentNodes, workflowInstance, token)
			}
			break
		}
	case constants.NodeTypeCc:
		nodeActionHistory.Type = constants.NodeActionTypeCc
		//抄送方法
		ccUserList := carbonCopy(node)
		if ccUserList != nil {
			nodeActionHistory.ActionInfo = transferActionInfoJson(map[string]interface{}{
				"ccUser": ccUserList,
			})
		}
		//fmt.Println("通知节点: " + node.NodeName)
	default:
	}

	model.DBWithToken(token).Model(&model.Node{}).Where("id = ?", nodeDb.Id).Update("status", nodeDb.Status)
	// 保存节点操作记录
	model.DBWithToken(token).Create(&nodeActionHistory)

	// 跳出当前节点,继续执行下一个节点
	if nodeDb.Status == constants.NodeStatusPass && node.ChildNode == nil && len(parentNodes) > 0 {
		return startNewNode(c, parentNodes[0], parentNodes[1:], workflowInstance, token)
	}

	if nodeDb.Status == constants.NodeStatusPass && len(parentNodes) == 0 && node.ChildNode == nil {
		// 前面没有进入到任何子节点,且父节点已经为空,则认为当前节点是结束节点
		// 结束节点,更新工作流实例状态
		model.DB().Model(&model.WorkflowInstance{}).Where("id = ?", workflowInstance.Id).Update("status", constants.WorkflowInstanceStatusComplete)
	}

	return nil
}

// transferActionInfoJson 转换actionInfo为json
func transferActionInfoJson(actionInfo map[string]interface{}) []byte {
	actionInfoJson, _ := json.Marshal(actionInfo)
	return actionInfoJson
}

// getAssigneeAndOperatorActionInfoJson 获取当前节点的审批人和操作人
func getAssigneeAndOperatorActionInfoJson(nodeDb *model.Node) []byte {
	actionInfo := getAssigneeAndOperatorActionInfoMap(nodeDb)
	actionInfoJson, _ := json.Marshal(actionInfo)
	return actionInfoJson
}

// getAssigneeAndOperatorActionInfoMap 获取当前节点的审批人和操作人
func getAssigneeAndOperatorActionInfoMap(nodeDb *model.Node) map[string]interface{} {
	nodeAssignees := getNodeAssignees(nodeDb)
	// 查询当前节点的操作人
	nodeOperators := getNodeOperators(nodeDb)

	actionInfo := map[string]interface{}{
		"assignee": nodeAssignees,
		"operator": nodeOperators,
	}
	return actionInfo
}

func getNodeOperators(nodeDb *model.Node) []model.NodeOperator {
	var nodeOperators []model.NodeOperator
	model.DB().Where("workflow_instance_id = ? and node_id = ?", nodeDb.WorkflowInstanceId, nodeDb.Id).Select("operator,operator_id,node_id").Find(&nodeOperators)
	return nodeOperators
}

func getNodeAssignees(nodeDb *model.Node) []model.NodeAssignee {
	var nodeAssignees []model.NodeAssignee
	model.DB().Where("workflow_instance_id = ? and node_id = ?", nodeDb.WorkflowInstanceId, nodeDb.Id).Select("name,target_id,node_id").Find(&nodeAssignees)
	return nodeAssignees
}

// transOperators 获取操作人
func transOperators(token *lib.Token) []map[string]interface{} {
	var operators []map[string]interface{}
	if token != nil {
		operators = append(operators, map[string]interface{}{
			"operatorId": token.UserId,
			"operator":   token.UserName,
		})
	}
	return operators
}

// getOperatorActionInfoJson 获取操作人
func getOperatorActionInfoJson(token *lib.Token) []byte {
	operators := transOperators(token)
	actionInfo := map[string]interface{}{
		"operator": operators,
	}
	actionInfoJson, _ := json.Marshal(actionInfo)
	return actionInfoJson
}

// 抄送
func carbonCopy(node Node) []CarbonCopyUser {
	if len(node.NodeUserList) == 0 {
		return nil
	}

	var ccUserList []CarbonCopyUser
	for _, user := range node.NodeUserList {
		switch user.Type {
		case 1: // 1代表具体用户
			// 这里可以添加发送通知的逻辑
			fmt.Printf("发送抄送通知给用户ID: %d, 名称: %s\n", user.TargetId, user.Name)
			ccUserList = append(ccUserList, CarbonCopyUser{
				UserName: user.Name,
				UserId:   user.TargetId,
				Source:   "user",
				SourceId: user.TargetId,
			})
		case 2: // 2代表角色
			// 获取角色下的所有用户
			userList, err := service.GetUserListByRoleId(user.TargetId)
			if err != nil {
				fmt.Printf("获取角色下的所有用户失败, 角色ID: %d, 错误: %s\n", user.TargetId, err.Error())
				continue
			}
			// 发送通知
			for _, u := range userList {
				ccUserList = append(ccUserList, CarbonCopyUser{
					UserName: u.Username,
					UserId:   u.Id,
					Source:   "role",
					SourceId: user.TargetId,
				})
				fmt.Printf("发送抄送通知给用户ID: %d, 名称: %s\n", u.Id, u.Username)
			}
		}
	}
	return ccUserList
}

// 计算条件节点的条件
func evalNodeCondition(conditionNode *Node, instance *model.WorkflowInstance) (any, error) {
	env := make(map[string]interface{})
	err := json.Unmarshal(instance.Variables, &env)
	if err != nil {
		return nil, err
	}
	program, err := expr.Compile(conditionNode.Condition, expr.Env(env))
	if err != nil {
		return nil, err
	}

	return expr.Run(program, env)
}

// DeleteWorkflow 删除工作流
func DeleteWorkflow(c *lib.GinContext) error {
	// 解析参数
	var req DeleteWorkflowReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	// 检查工作流是否存在
	var workflow model.Workflow
	result := model.DBWithGinContext(c).First(&workflow, req.Id)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "工作流不存在")
	}

	// 检查是否有正在运行的工作流实例
	var count int64
	model.DBWithGinContext(c).Model(&model.WorkflowInstance{}).Where("workflow_id = ? AND status != ?", req.Id, constants.WorkflowInstanceStatusComplete).Count(&count)
	if count > 0 {
		return response.JsonFail(c, "存在正在运行的工作流实例，无法删除")
	}

	// 执行逻辑删除
	result = model.DBWithGinContext(c).Model(&workflow).Update("deleted", 1)
	if result.Error != nil {
		c.Logger().Error("删除工作流失败: " + result.Error.Error())
		return response.JsonFail(c, "删除工作流失败")
	}

	return response.JsonOk(c, nil, "删除成功")
}
